/*******************************************************************/
/* @ All Rights Reserved Copyright (C) 2014 broada,Co.,Ltd.        */
/*                                                                 */
/*  NAME      = frlua_config.c                                     */
/*  NOTE      = lua配置管理                                        */
/*  DATE      = 2015/06/17 by guojq                                */
/*******************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>

#include "frcomm.h"
#include "frame_cfg.h"
#include "frsutl.h"
#include "frmem.h"
#include "frlog.h"
#include "frcmd_server.h"
#include "frxml_parse.h"
#include "frlua_config.h"
#include "frlua_hook.h"

#define LUA_ACTION_ADD    0
#define LUA_ACTION_DEL    1
#define LUA_ACTION_CLEAR  2

typedef struct __Lua_info {
    int i_action;  //(0:add/1:del)
    u_int ip;
    char *port;
    char *lua;
} Lua_info;

FR_STATIC Frlist_header *g_p_lst_lua_cnf = NULL;
FR_STATIC unsigned long g_ul_lua_version = 1;
FR_STATIC pthread_rwlock_t g_lua_rwlock;

FR_STATIC Frlist_header g_lst_cmd_lua_info;

unsigned long frlua_config_version(void)
{
    return g_ul_lua_version;
}

FR_STATIC void __frlua_version_set(void)
{
    g_ul_lua_version++;
}

void frlua_read_lock(void)
{
    pthread_rwlock_rdlock(&g_lua_rwlock);
}

void frlua_read_unlock(void)
{
    pthread_rwlock_unlock(&g_lua_rwlock);
}

/*******************************************************************************
*  FUNC     :  释放链表节点
*  ARGS     :  Frlist_node* node   需要释放的链表节点
*  RTN      :  void
*  NOTE     :
*******************************************************************************/
FR_STATIC void __lua_info_node_free(Frlist_node* node)
{
    Lua_info *p_st_info = NULL;

    if (node == NULL || node->data == NULL)
        return;
    p_st_info = (Lua_info *)node->data;
    
    if (p_st_info->port)
        frfree(p_st_info->port);
    if (p_st_info->lua)
        frfree(p_st_info->lua);
    frfree(p_st_info);
    return;
}

FR_STATIC void __lua_info_free(Lua_cfg **pp_lua_info)
{
    Lua_cfg *p_lua_info = NULL;
    if (pp_lua_info && *pp_lua_info)
    {
        p_lua_info = *pp_lua_info;
        if (p_lua_info->p_file)
            frfree(p_lua_info->p_file);
        if (p_lua_info->p_lua)
            frfree(p_lua_info->p_lua);
        if(p_lua_info->p_lua_handle)
            lua_close(p_lua_info->p_lua_handle);
        pthread_spin_destroy(&p_lua_info->splock);

        frfree(p_lua_info);
        *pp_lua_info = NULL;
    }
}

/*******************************************************************************
*  FUNC     :  释放链表节点
*  ARGS     :  Frlist_node* node   需要释放的链表节点
*  RTN      :  void
*  NOTE     :
*******************************************************************************/
FR_STATIC void __lua_node_free(Frlist_node* node)
{
    Lua_cfg *p_st_lua = NULL;

    if (node == NULL || node->data == NULL)
        return;
    p_st_lua = (Lua_cfg *)node->data;
    
    __lua_info_free(&p_st_lua);
    
    return;
}


FR_STATIC int __lua_find_node(Frlist_node* node, const void *p_compare_data)
{
    Lua_cfg *p_st_new = NULL;
    Lua_cfg *p_st_node_lua = NULL;

    if (node == NULL || p_compare_data == NULL || node->data == NULL)
        return 1;

    p_st_node_lua = (Lua_cfg *)node->data;
    p_st_new = (Lua_cfg *)p_compare_data;
    
    //跳过已经删除的节点
    if (p_st_node_lua->flg_del)
        return 1;

    if (p_st_node_lua->ip != p_st_new->ip)
        return 1;
    
    if (p_st_node_lua->port_start != p_st_new->port_start || p_st_node_lua->port_end != p_st_new->port_end)
        return 1;
    
    return 0;
}

/*******************************************************************************
*  FUNC     :  查找目标ip是否在链表中
*  ARGS     :  p_st_head            链表头
*           :  ui_ip                ip地址
*           :  us_port              端口
*  RTN      :  FR_SUCC              在链表中
*              FR_FAIL              不在链表中
*  NOTE     :  
*******************************************************************************/
FR_STATIC Frlist_node *__frlua_find(Frlist_header *p_st_head, u_int ui_ip, u_short i_port_start, u_short i_port_end)
{
    Frlist_node *p_st_find = NULL;
    Lua_cfg st_lua_cache;
    
    memset(&st_lua_cache, 0x00, sizeof(Lua_cfg));
    st_lua_cache.ip = ui_ip;
    st_lua_cache.port_start = i_port_start;
    st_lua_cache.port_end = i_port_end;
    
    p_st_find = frlist_find(p_st_head, (void *)&st_lua_cache, __lua_find_node);
    if (p_st_find == NULL)
        return NULL;
    
    return p_st_find;
}

FR_STATIC void __ip2filename(u_int ui_ip, char *p_filename)
{
    char *p_ip = int_ntoa(ui_ip);
    char *p_tmp = NULL;
    
    strcpy(p_filename, p_ip);
    p_tmp = strchr(p_filename, '.');
//    while (p_tmp)
//    {
//        *p_tmp = '_';
//        p_tmp = strchr(p_tmp + 1, '.');
//    }
    return;
}

/*******************************************************************************
*  FUNC     :  把lua的内容写到文件里
*  ARGS     :  p_info               lua信息的结构体
*  RTN      :  FR_SUCC              
*              FR_FAIL              
*  NOTE     :  
*******************************************************************************/
FR_STATIC int __frlua_add2file(Lua_cfg *p_info)
{
    char arr_dir[256];
    char arr_dir_name[128];
    char arr_file_name[256];
    char arr_cmd[256];
    FILE *fp = NULL;
    int i_status = 0;
    
    memset(arr_dir_name, 0x00, sizeof(arr_dir_name));
    memset(arr_dir, 0x00, sizeof(arr_dir));
    __ip2filename(p_info->ip, arr_dir);
    
    snprintf(arr_dir_name, sizeof(arr_dir_name), "%s/%s", APM_CFG_DIR_LUA, arr_dir);
    snprintf(arr_file_name, sizeof(arr_file_name), "%s/lua_%d-%d.lua",  arr_dir_name, p_info->port_start, p_info->port_end);
    
    if (access(arr_file_name, 0))
    {
        snprintf(arr_cmd, sizeof(arr_cmd), "%s -p %s", FR_CMD_MKDIR, arr_dir_name);
        i_status = system(arr_cmd);
        if (i_status < 0)
            return FR_FAIL;
    }
    fp = fopen(arr_file_name, "w+");
    if (fp == NULL)
        return FR_FAIL;
    
    fwrite(p_info->p_lua, strlen(p_info->p_lua), 1, fp);
    
    fclose(fp);
    
    if (p_info->p_file)
        frfree(p_info->p_file);
    p_info->p_file = frstrdup(arr_file_name);
    
    return FR_SUCC;
}

FR_STATIC int __frlua_xml_add(Lua_cfg *p_lua_info)
{
    int i_ret = 0;
    char arr_value[512];
    
    if (p_lua_info == NULL || p_lua_info->p_file == NULL)
        return FR_FAIL;
    
    snprintf(arr_value, sizeof(arr_value), "%s %d-%d %s"
           , int_ntoa(p_lua_info->ip), p_lua_info->port_start, p_lua_info->port_end
           , p_lua_info->p_file);
    
    i_ret = frxml_insert2doc_content(APM_CFG_FILENAME_ANALYZER, APM_CFG_ANALYZER_XPATH_LUA, APM_CFG_LUA_KEY_RULE, arr_value);
    
    return i_ret;
}

FR_STATIC void __frlua_del_lua_head(char *p_data)
{
    char *p_pos=NULL;
    int i_len=0;
    if(p_data == NULL || *p_data == '\0')
        return;

    //确认有没有#!/usr/bin/lua
    if(strncmp(p_data, "#!", 2))
        return;

    //去除 #!/usr/bin/lua
    p_pos = strchr(p_data, '\n');
    if(p_pos == NULL)
    {
        *p_data = '\0';
        return;
    }

    i_len = strlen(p_data) - (p_pos-p_data);
    if(i_len > 0)
        memmove(p_data, p_pos+1, i_len);
    return;
}

/*******************************************************************************
*  FUNC     :  把lua的内容写到内存中并保存到文件中
*  ARGS     :  ui_ip                ip地址
*           :  us_port              端口
*           :  p_lua                lua内容
*  RTN      :  FR_SUCC              
*              FR_FAIL              
*  NOTE     :  
*******************************************************************************/
FR_STATIC int __frlua_config_add(u_int ui_ip, const char *p_port, char *p_lua)
{
    Lua_cfg *p_st_lua_info = NULL;
    Frlist_node *p_st_node_find = NULL;
    Frlist_node *p_st_node_new = NULL;
    u_short i_port_start = 0, i_port_end = 0;
    
    if (p_lua == NULL)
        return FR_FAIL;
    
    if (p_port)
        iptools_parse_portrange(p_port, &i_port_start, &i_port_end);
    
    p_st_node_find = __frlua_find(g_p_lst_lua_cnf, ui_ip, i_port_start, i_port_end);
    if (p_st_node_find && p_st_node_find->data)
    {
        p_st_lua_info = (Lua_cfg *)p_st_node_find->data;

        pthread_spin_lock(&p_st_lua_info->splock);
        //存在该ip的节点

        //更新lua的内容到缓存节点
        if (p_st_lua_info->p_lua)
            frfree(p_st_lua_info->p_lua);
        p_st_lua_info->p_lua = frstrdup(p_lua);
        __frlua_del_lua_head(p_st_lua_info->p_lua);

        //更新lua的内容到文件
        if (__frlua_add2file(p_st_lua_info) != FR_SUCC)
        {
            pthread_spin_unlock(&p_st_lua_info->splock);
            return FR_FAIL;
        }

        if(p_st_lua_info->p_lua_handle)
            lua_close(p_st_lua_info->p_lua_handle);
        p_st_lua_info->p_lua_handle = frlua_create_lua_stat(p_st_lua_info->p_lua, p_st_lua_info->p_file);
        if (p_st_lua_info->flg_del)
        {
            //更新lua的内容到xml
            if (__frlua_xml_add(p_st_lua_info) != FR_SUCC)
            {
                if(p_st_lua_info->p_lua)
                    frfree(p_st_lua_info->p_lua);
                frfree(p_st_lua_info);
                return FR_FAIL;
            }
        }
        p_st_lua_info->flg_del = 0;
        FRLOG_INFO_DETAIL("lua add1 ip=%s,port=%d-%d,file=%s"
                , int_ntoa(p_st_lua_info->ip), p_st_lua_info->port_start, p_st_lua_info->port_end, p_st_lua_info->p_file);

        __frlua_version_set();

        pthread_spin_unlock(&p_st_lua_info->splock);
        return FR_SUCC;
    }
    
    p_st_lua_info = (Lua_cfg *)frmalloc(sizeof(Lua_cfg));
    if (p_st_lua_info == NULL)
        return FR_FAIL;
    
    memset(p_st_lua_info, 0x00, sizeof(Lua_cfg));
    p_st_lua_info->ip = ui_ip;
    p_st_lua_info->port_start = i_port_start;
    p_st_lua_info->port_end = i_port_end;
    p_st_lua_info->p_lua = frstrdup(p_lua);
    __frlua_del_lua_head(p_st_lua_info->p_lua);
    
    //添加lua的内容到文件中
    if (__frlua_add2file(p_st_lua_info) != FR_SUCC)
    {
        if(p_st_lua_info->p_lua)
            frfree(p_st_lua_info->p_lua);
        frfree(p_st_lua_info);
        return FR_FAIL;
    }
    //更新lua的内容到xml
    if (__frlua_xml_add(p_st_lua_info) != FR_SUCC)
    {
        if(p_st_lua_info->p_lua)
            frfree(p_st_lua_info->p_lua);
        frfree(p_st_lua_info);
        return FR_FAIL;
    }
    
    p_st_node_new = frlist_node_create(p_st_lua_info);
    if (p_st_node_new == NULL)
    {
        if(p_st_lua_info->p_lua)
            frfree(p_st_lua_info->p_lua);
        frfree(p_st_lua_info);
        return FR_FAIL;
    }
    pthread_spin_init(&p_st_lua_info->splock, 0);
    p_st_lua_info->p_lua_handle = frlua_create_lua_stat(p_st_lua_info->p_lua, p_st_lua_info->p_file);
    
    frlist_add_tail(g_p_lst_lua_cnf, p_st_node_new);
    __frlua_version_set();

    FRLOG_INFO_DETAIL("lua add ip=%s,port=%d-%d,file=%s"
            , int_ntoa(p_st_lua_info->ip), p_st_lua_info->port_start, p_st_lua_info->port_end, p_st_lua_info->p_file);
    
    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  删除内存中和文件里的lua信息
*  ARGS     :  ui_ip                ip地址
*           :  us_port              端口
*  RTN      :  FR_SUCC              
*              FR_FAIL              
*  NOTE     :  
*******************************************************************************/
FR_STATIC int __frlua_config_del(u_int ui_ip, const char *p_port)
{
    Lua_cfg *p_lua_cfg = NULL;
    Frlist_node *p_st_find = NULL;
    u_short i_port_start = 0, i_port_end = 0;
    
    if (p_port)
        iptools_parse_portrange(p_port, &i_port_start, &i_port_end);
        
    p_st_find = __frlua_find(g_p_lst_lua_cnf, ui_ip, i_port_start, i_port_end);
    if (p_st_find && p_st_find->data)
    {
        char arr_buff[256];
        p_lua_cfg = (Lua_cfg *)p_st_find->data;

        remove(p_lua_cfg->p_file);

        snprintf(arr_buff, sizeof(arr_buff), "%s %d-%d %s"
               , int_ntoa(p_lua_cfg->ip), p_lua_cfg->port_start, p_lua_cfg->port_end
               , p_lua_cfg->p_file);
        frxml_del2doc_one_cont(APM_CFG_FILENAME_ANALYZER, APM_CFG_ANALYZER_XPATH_LUA, APM_CFG_LUA_KEY_RULE, arr_buff);

        FRLOG_INFO_DETAIL("lua del ip=%s,port=%d-%d"
                , int_ntoa(p_lua_cfg->ip), p_lua_cfg->port_start, p_lua_cfg->port_end);
        p_lua_cfg->flg_del = 1;
        __frlua_version_set();
        return FR_SUCC;
    }

    return FR_SUCC;
}

FR_STATIC int __list_node_lua_delete(Frlist_node *p_st_node, const void *p_data)
{
    Lua_cfg *p_lua_cfg = NULL;

    if(p_st_node && p_st_node->data)
    {
        p_lua_cfg = (Lua_cfg *) p_st_node->data;
        remove(p_lua_cfg->p_file);
        p_lua_cfg->flg_del = 1;
        return 1;
    }

    return 0;
}
/*******************************************************************************
*  FUNC     :  清空内存中和文件里的lua信息
*  ARGS     :  ui_ip                ip地址
*           :  us_port              端口
*  RTN      :  FR_SUCC
*              FR_FAIL
*  NOTE     :
*******************************************************************************/
FR_STATIC int __frlua_config_clear(void)
{
    frlist_run(g_p_lst_lua_cnf, NULL, __list_node_lua_delete);

    frxml_del2doc_all_cont(APM_CFG_FILENAME_ANALYZER, APM_CFG_ANALYZER_XPATH_LUA, APM_CFG_LUA_KEY_RULE);

    FRLOG_INFO_DETAIL("lua clear");
    __frlua_version_set();

    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  清空内存中和文件里的lua信息
*  ARGS     :
*  RTN      :  FR_SUCC
*              FR_FAIL
*  NOTE     :
*******************************************************************************/
int frlua_clear_all(char **pp_result)
{
    frlist_run(g_p_lst_lua_cnf, NULL, __list_node_lua_delete);

    frxml_del2doc_all_cont(APM_CFG_FILENAME_ANALYZER, APM_CFG_ANALYZER_XPATH_LUA, APM_CFG_LUA_KEY_RULE);

    FRLOG_INFO_DETAIL("lua clear all");
    __frlua_version_set();

    return FR_SUCC;
}

FR_STATIC int __frlua_read_file(Lua_cfg *p_lua_info)
{
    FILE *fp = NULL;
    int i_file_size = 0;
    char *p_lua_txt = NULL;
    int i_read = 0;

    if (p_lua_info == NULL || p_lua_info->p_file == NULL)
        return FR_FAIL;

    fp = fopen(p_lua_info->p_file, "r");
    if (fp == NULL)
        return FR_FAIL;
    
    //取得文件长度
    fseek(fp, 0L, SEEK_END);
    i_file_size = ftell(fp);
    rewind(fp);
    
    p_lua_txt = (char *)frmalloc(i_file_size + 1);
    if (p_lua_txt == NULL)
    {
        fclose(fp);
        return FR_FAIL;
    }
    memset(p_lua_txt, 0x00, i_file_size + 1);
    
    i_read = fread(p_lua_txt, sizeof(char), i_file_size, fp);
    if (i_read != i_file_size)
    {
        frfree(p_lua_txt);
        fclose(fp);
        return FR_FAIL;
    }
    __frlua_del_lua_head(p_lua_txt);
    p_lua_info->p_lua = p_lua_txt;
    
    fclose(fp);
    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  解析lua一行的数据
*              格式：IP 端口段 路径
*                例：172.16.0.31 80-80 172_16_0_31/lua_80-80_1433
*  ARGS     :  p_line                   一行xml数据
*           :  pp_lua_info              lua信息的结构体
*  RTN      :  FR_SUCC              
*              FR_FAIL              
*  NOTE     :  
*******************************************************************************/
FR_STATIC int __frlua_analyse_xml(char *p_line, Lua_cfg **pp_lua_info)
{
    Lua_cfg *p_lua_info = NULL;
    char *p_tmp = NULL;
    char *p_file = NULL;
    u_int ui_ip = 0;
    u_short i_port_start = 0, i_port_end = 0;
    
    if (p_line == NULL)
        return FR_FAIL;
    
    p_tmp = strchr(p_line, ' ');
    if (p_tmp == NULL)
        return FR_FAIL;
    //取得ip
    ui_ip = iptools_parse_ipaddr(p_line);
    
    p_tmp++;
    //取得端口
    iptools_parse_portrange(p_tmp, &i_port_start, &i_port_end);
    
    p_tmp = strchr(p_tmp, ' ');
    if (p_tmp == NULL)
        return FR_FAIL;
    p_tmp++;
    
    //取得文件名
    p_file = frstrdup(p_tmp);
    if (p_file == NULL)
        return FR_FAIL;
    
    p_lua_info = (Lua_cfg *)frmalloc(sizeof(Lua_cfg));
    if (p_lua_info == NULL)
    {
        frfree(p_file);
        return FR_FAIL;
    }
    memset(p_lua_info, 0x00, sizeof(Lua_cfg));
    p_lua_info->ip = ui_ip;
    p_lua_info->port_start = i_port_start;
    p_lua_info->port_end = i_port_end;
    p_lua_info->p_file = p_file;

    pthread_spin_init(&p_lua_info->splock, 0);
    p_lua_info->refcnt = 0;
    p_lua_info->flg_del=0;

    *pp_lua_info = p_lua_info;
    return FR_SUCC;
}

int frlua_config_add(u_int ui_ip, const char *p_port, const char *p_lua, char **pp_result)
{
    Frlist_node *p_st_new = NULL;
    Lua_info *p_st_info_tmp;
    char *p_lua_data=NULL, *p_msg=NULL;
    
    if (p_lua == NULL)
        return FR_FAIL;
    
    p_lua_data = frstrdup(p_lua);
    if(p_lua_data == NULL)
    {
        FRLOG_ERROR_DETAIL("frstrdup error");
        return FR_FAIL;
    }
    __frlua_del_lua_head(p_lua_data);

    if (frlua_check_lua(p_lua_data, &p_msg) != FR_SUCC)
    {
        if(p_msg)
            *pp_result = p_msg;
        else
            *pp_result = frstrdup(ERR_CHK_LUA);
        frfree(p_lua_data);
        return FR_FAIL;
    }
    if(p_msg)
    {
        frfree(p_msg);
        p_msg = NULL;
    }
    
    p_st_info_tmp = (Lua_info *) frmalloc(sizeof(Lua_info));
    if (p_st_info_tmp == NULL)
    {
        *pp_result = frstrdup(ERR_MALLOC_FAILED);
        frfree(p_lua_data);
        return FR_FAIL;
    }
        
    memset(p_st_info_tmp, 0x00, sizeof(Lua_info));
    p_st_info_tmp->i_action = LUA_ACTION_ADD;
    p_st_info_tmp->ip = ui_ip;
    if (p_port)
        p_st_info_tmp->port = frstrdup(p_port);
    else
        p_st_info_tmp->port = NULL;
    p_st_info_tmp->lua = p_lua_data;
    
    pthread_rwlock_wrlock(&g_lua_rwlock);
    
    p_st_new = frlist_node_create(p_st_info_tmp);
    if (p_st_new == NULL)
    {
        if (p_st_info_tmp->port)
            frfree(p_st_info_tmp->port);
        frfree(p_st_info_tmp->lua);
        pthread_rwlock_unlock(&g_lua_rwlock);
        *pp_result = frstrdup(ERR_MALLOC_FAILED);
        return FR_FAIL;
    }
    frlist_add_tail(&g_lst_cmd_lua_info, p_st_new);
    
    pthread_rwlock_unlock(&g_lua_rwlock);
    
    return FR_SUCC;
}

int frlua_config_del(u_int ui_ip, const char *p_port, char **pp_result)
{
    Frlist_node *p_st_new = NULL;
    Lua_info *p_st_info_tmp;
    
    p_st_info_tmp = (Lua_info *) frmalloc(sizeof(Lua_info));
    if (p_st_info_tmp == NULL)
    {
        *pp_result = frstrdup(ERR_MALLOC_FAILED);
        return FR_FAIL;
    }
        
    memset(p_st_info_tmp, 0x00, sizeof(Lua_info));
    p_st_info_tmp->i_action = LUA_ACTION_DEL;
    p_st_info_tmp->ip = ui_ip;
    if (p_port)
        p_st_info_tmp->port = frstrdup(p_port);
    else
        p_st_info_tmp->port = NULL;
    
    pthread_rwlock_wrlock(&g_lua_rwlock);
    
    p_st_new = frlist_node_create(p_st_info_tmp);
    if (p_st_new == NULL)
    {
        if (p_st_info_tmp->port)
            frfree(p_st_info_tmp->port);
        pthread_rwlock_unlock(&g_lua_rwlock);
        *pp_result = frstrdup(ERR_MALLOC_FAILED);
        return FR_FAIL;
    }
    frlist_add_tail(&g_lst_cmd_lua_info, p_st_new);
    
    pthread_rwlock_unlock(&g_lua_rwlock);
    
    return FR_SUCC;
}

int frlua_config_clear(char **pp_result)
{
    Frlist_node * p_st_new = NULL;
    Lua_info *p_st_info_tmp;

    p_st_info_tmp = (Lua_info *) frmalloc(sizeof(Lua_info));
    if (p_st_info_tmp == NULL) {
        *pp_result = frstrdup(ERR_MALLOC_FAILED);
        return FR_FAIL;
    }

    memset(p_st_info_tmp, 0x00, sizeof(Lua_info));
    p_st_info_tmp->i_action = LUA_ACTION_CLEAR;

    pthread_rwlock_wrlock(&g_lua_rwlock);

    p_st_new = frlist_node_create(p_st_info_tmp);
    if (p_st_new == NULL)
    {
        if (p_st_info_tmp->port)
            frfree(p_st_info_tmp->port);
        pthread_rwlock_unlock(&g_lua_rwlock);
        *pp_result = frstrdup(ERR_MALLOC_FAILED);
        return FR_FAIL;
    }
    frlist_add_tail(&g_lst_cmd_lua_info, p_st_new);

    pthread_rwlock_unlock(&g_lua_rwlock);

    return FR_SUCC;
}

int do_lua_commit(char **pp_result)
{
    Frlist_node *p_st_tmp = NULL;
    Lua_info *p_st_info_tmp = NULL;

    pthread_rwlock_wrlock(&g_lua_rwlock);
    
    if (frlist_size(&g_lst_cmd_lua_info) == 0)
    {
        pthread_rwlock_unlock(&g_lua_rwlock);
        return FR_SUCC;
    }
    
    p_st_tmp = FRLIST_FIRST_NODE(&g_lst_cmd_lua_info);
    while(p_st_tmp)
    {
        p_st_info_tmp = (Lua_info*)FRLIST_GET_NODE_DATA(p_st_tmp);
        if (p_st_info_tmp)
        {
            if (p_st_info_tmp->i_action == LUA_ACTION_ADD)
                __frlua_config_add(p_st_info_tmp->ip, p_st_info_tmp->port, p_st_info_tmp->lua);
            else if (p_st_info_tmp->i_action == LUA_ACTION_DEL)
                __frlua_config_del(p_st_info_tmp->ip, p_st_info_tmp->port);
            else
                __frlua_config_clear();
        }
        p_st_tmp = FRLIST_NEXT_NODE(p_st_tmp);
    }
    frlist_remove_all(&g_lst_cmd_lua_info, __lua_info_node_free);
    
    pthread_rwlock_unlock(&g_lua_rwlock);
    
    return FR_SUCC;
}

int do_lua_rollback(void)
{
    pthread_rwlock_wrlock(&g_lua_rwlock);
    frlist_remove_all(&g_lst_cmd_lua_info, __lua_info_node_free);
    pthread_rwlock_unlock(&g_lua_rwlock);
    return FR_SUCC;
}


/*******************************************************************************
*  FUNC     :  加载lua配置到内存
*  ARGS     :  
*  RTN      :  FR_SUCC
*              FR_FAIL
*  NOTE     :
*******************************************************************************/
int frlua_config_load(void)
{
    Frlist_header *p_xml_head = NULL;
    Frlist_node *p_st_node = NULL;
    Frvar_field *p_st_field_tmp = NULL;
    
    if (frxml_get_string_list(APM_CFG_FILENAME_ANALYZER, APM_CFG_ANALYZER_XPATH_LUA, APM_CFG_LUA_KEY_RULE, &p_xml_head) == FR_FAIL)
    {
        FRLOG_ERROR_DETAIL("file [%s] error", APM_CFG_FILENAME_ANALYZER);
        return FR_FAIL;
    }
    
    p_st_node = FRLIST_FIRST_NODE(p_xml_head);
    while(p_st_node)
    {
        p_st_field_tmp = (Frvar_field *)FRLIST_GET_NODE_DATA(p_st_node);
        if (p_st_field_tmp)
        {
            Lua_cfg *p_lua_info = NULL;
            Frlist_node *p_st_new = NULL;
            
            //解析一行数据取得lua对应文件名
            if (__frlua_analyse_xml(p_st_field_tmp->field_value.p_value, &p_lua_info) != FR_SUCC)
                goto err;
            
            //读取lua文件，把lua文件内容放到内存节点中
            if (__frlua_read_file(p_lua_info)!= FR_SUCC)
            {
                __lua_info_free(&p_lua_info);
                goto err;
            }
            
            //添加到链表中
            p_st_new = frlist_node_create(p_lua_info);
            if (p_st_new == NULL)
            {
                __lua_info_free(&p_lua_info);
                goto err;
            }
            p_lua_info->p_lua_handle = frlua_create_lua_stat(p_lua_info->p_lua, p_lua_info->p_file);
            
            pthread_rwlock_wrlock(&g_lua_rwlock);
            frlist_add_tail(g_p_lst_lua_cnf, p_st_new);
            pthread_rwlock_unlock(&g_lua_rwlock);
        }
        p_st_node = FRLIST_NEXT_NODE(p_st_node);
    }
    frxml_free_list(&p_xml_head);
    return FR_SUCC;
err:
    frxml_free_list(&p_xml_head);
    return FR_FAIL;
}

FR_STATIC int __lua_cfg_check_node(Frlist_node* node, const void *p_compare_data)
{
    Lua_cfg *p_st_new = NULL;
    Lua_cfg *p_st_node_lua = NULL;

    if (node == NULL || p_compare_data == NULL || node->data == NULL)
        return 1;

    p_st_node_lua = (Lua_cfg *)node->data;
    p_st_new = (Lua_cfg *)p_compare_data;
    
    if(p_st_node_lua->flg_del)
        return 1;

    if (p_st_node_lua->ip != 0 && p_st_node_lua->ip != p_st_new->ip)
        return 1;
    
    //只有
    if (p_st_node_lua->port_start && p_st_node_lua->port_end)
    {
        if (p_st_new->port_start < p_st_node_lua->port_start || p_st_new->port_start > p_st_node_lua->port_end)
            return 1;
    }
    
    return 0;
}
/*******************************************************************************
*  FUNC     :  查询lua信息
*  ARGS     :  
*  RTN      :  成功:Lua_cfg*; 失败:NULL
*  NOTE     :  需要外面调用frlua_read_lock加锁和frlua_read_unlock解锁
*           :  pp_lua外面使用完不需要释放内存
*******************************************************************************/
Lua_cfg* frlua_config_lookup(u_int ui_ip, u_short us_port)
{
    Lua_cfg st_input_info;
    Lua_cfg *p_lua_out = NULL;
    Frlist_node *p_st_find = NULL;
    
    if (ui_ip == 0)
        return NULL;
    
    memset(&st_input_info, 0x00, sizeof(Lua_cfg));
    st_input_info.ip = ui_ip;
    st_input_info.port_start = us_port;
    st_input_info.port_end = us_port;
    
    pthread_rwlock_rdlock(&g_lua_rwlock);
    p_st_find = frlist_find(g_p_lst_lua_cnf, (void *)&st_input_info, __lua_cfg_check_node);
    if (p_st_find == NULL || p_st_find->data == NULL)
    {
        pthread_rwlock_unlock(&g_lua_rwlock);
        return NULL;
    }
    
    p_lua_out = (Lua_cfg *)p_st_find->data;
    __sync_fetch_and_add(&p_lua_out->refcnt, 1);

    pthread_rwlock_unlock(&g_lua_rwlock);

    return p_lua_out;
}

void frlua_config_put(Lua_cfg *p_lua_cfg)
{
    if(p_lua_cfg == NULL)
        return;

    __sync_fetch_and_sub(&p_lua_cfg->refcnt, 1);
    return;
}

/*******************************************************************************
*  FUNC     :  从链表中删除lua配置信息
*  ARGS     :
*  RTN      :
*  NOTE     :  删除条件 flg_del==1 && p_st_lua_cfg->refcnt <= 0
*******************************************************************************/
void frlua_chk_del()
{
    Frlist_node *p_st_node_do=NULL, *p_st_node_next=NULL;
    Lua_cfg *p_st_lua_cfg=NULL;

    pthread_rwlock_wrlock(&g_lua_rwlock);

    p_st_node_do = FRLIST_FIRST_NODE(g_p_lst_lua_cnf);
    while(p_st_node_do)
    {
        p_st_node_next = FRLIST_NEXT_NODE(p_st_node_do);

        p_st_lua_cfg =  (Lua_cfg*)FRLIST_GET_NODE_DATA(p_st_node_do);
        if(p_st_lua_cfg == NULL
           || p_st_lua_cfg->flg_del == 0
           || p_st_lua_cfg->refcnt > 0)
        {
            p_st_node_do = p_st_node_next;
            continue;
        }
        FRLOG_INFO_DETAIL("del lua[%s]", p_st_lua_cfg->p_file);
        frlist_node_free(g_p_lst_lua_cnf, p_st_node_do, 1, __lua_node_free);

        p_st_node_do = p_st_node_next;
    }

    pthread_rwlock_unlock(&g_lua_rwlock);
    return ;
}

/*******************************************************************************
*  FUNC     :  初始化lua配置信息
*  ARGS     :  
*  RTN      :  FR_SUCC
*              FR_FAIL
*  NOTE     :
*******************************************************************************/
int frlua_config_init(void)
{
    if (pthread_rwlock_init(&g_lua_rwlock, NULL) != 0)
    {
        FRLOG_ERROR_DETAIL("pthread_rwlock_init failed");
        return FR_FAIL;
    }

    g_p_lst_lua_cnf = frlist_create();
    if (g_p_lst_lua_cnf == NULL)
    {
        pthread_rwlock_destroy(&g_lua_rwlock);
        FRLOG_ERROR_DETAIL("frlist create failed");
        return FR_FAIL;
    }
    frlist_header_init(&g_lst_cmd_lua_info);

    return FR_SUCC;
}

void frlua_config_destroy(void)
{
    pthread_rwlock_destroy(&g_lua_rwlock);
    frlist_remove_all(&g_lst_cmd_lua_info, __lua_info_node_free);
    frlist_destroy(g_p_lst_lua_cnf, __lua_node_free);
}
